#include "texture_shader.hh"
#include <iostream>
#include <stdio.h>
#include <SDL/SDL_image.h>

using namespace std;
using namespace cgmath;

texture_shader::texture_shader (const char* tex_file)
{
  //init diffuse vector
  diffuse = vec(0.0,0.0,0.0);

  //Load the texture
  if(IMG_Init(IMG_INIT_JPG)) 
    {
      
      texture = IMG_Load(tex_file);
      
      if(texture == NULL)
	{
	cout << "Error reading file: " << IMG_GetError() << "\n";
	}      
      else
	{
	cout << "Texture read succesfully\n";
	}
    }
  
}



// in_dir points from source (e.g. light sample) to this point.
vector_3d texture_shader::bsdf (const surface_point& point,
				const vector_3d&     in_dir,
				const vector_3d&  /* out_dir */)
{
  cgmath::vector_3d c(0.0);
  double cos_theta = -cgmath::dot(in_dir, point.normal);

  double r = 0.6;
  double g = 0.6;
  double b = 0.6;
  int ux = int(texture->w * point.u);
  int vy = int(texture->h * point.v);
  Uint8 ir = 0;
  Uint8 ig = 0;
  Uint8 ib = 0;
  Uint32 pixel;
  Uint8 *p = (Uint8 *)texture->pixels + vy * texture->pitch + ux * texture->format->BytesPerPixel;

  switch (texture->format->BytesPerPixel) {
  case 1:
    pixel = *p;
    break;

  case 2:
    pixel = *(Uint16 *)p;
    break;

  case 3:
    if (SDL_BYTEORDER == SDL_BIG_ENDIAN)
      pixel =  p[0] << 16 | p[1] << 8 | p[2];
    else
      pixel =  p[0] | p[1] << 8 | p[2] << 16;
    
  case 4:
    pixel = *(Uint32 *)p;
  default:
    pixel = *(Uint32 *)p;
  }

  SDL_GetRGB(pixel, texture->format, &ir, &ig, &ib);

  r = (double)((unsigned int)ir / 255.0);
  g = (double)((unsigned int)ig / 255.0);
  b = (double)((unsigned int)ib / 255.0);

  if (cos_theta > 0)
    // pi is a normalizing factor
    c = (cos_theta / M_PI) * vec(r,g,b);

  return c;
}


  
void texture_shader::sample_bsdf (const surface_point& point,
				  unsigned             num_samples,
				  const vector_3d&     out_dir,
				  bsdf_samples& samples)
{
  samples.resize (num_samples);
  matrix_3d R;
  // The rotation aligns the surface normal with the z axis, so that
  // the sample will be on the upper sample in a coordinate system
  // where the normal is aligned with the z axis.
  R = rotate (vec(0.0, 0.0, 1.0), point.normal);
  for (unsigned i = 0; i < samples.size(); ++i)
    samples[i] = bsdf_sample (R * lambert_sample(), diffuse);
}
